from rest_framework import status
from rest_framework_mongoengine.generics import GenericAPIView
from rest_framework.response import Response
from rest_framework.settings import api_settings

from models.user import User


class APIView(GenericAPIView):
    check_user = False

    def __init__(self, *args, **kwargs):
        self.request = None
        self.url_args = {}
        super(APIView, self).__init__(*args, **kwargs)

    def perform_create(self, serializer):
        serializer.save()

    def get_success_headers(self, data):
        try:
            return {'Location': str(data[api_settings.URL_FIELD_NAME])}
        except (TypeError, KeyError):
            return {}

    def _initialize(self, request, *args, **kwargs):
        self.request = request
        self.request.data['user_id'] = self.request.user.user_id
        self.user_query = {}
        if not self.request.user.is_superuser:
            self.user_query['user_id'] = self.request.user.user_id
        elif self.request.user.is_superuser and self.request.user.username != "admin":
            user_ids = [u.user_id for u in User.objects.filter(parent_id=self.request.user.user_id)]
            user_ids.append(self.request.user.user_id)
            self.user_query['user_id'] = {"$in": user_ids}
        if self.check_user and getattr(self, 'queryset', None):
            self.queryset = self.queryset.filter(**self.user_query)
        self.url_args = kwargs

        filter_func = getattr(self, 'filter_request', None)
        if filter_func:
            filter_func()

    def get_serializer(self, *args, **kwargs):
        serializer = super(APIView, self).get_serializer(*args, **kwargs)
        serializer.request = self.request
        return serializer

    def finalize_response(self, request, response, *args, **kwargs):
        filter_func = getattr(self, 'filter_response', None)
        if filter_func:
            response = filter_func(response)
        return super(APIView, self).finalize_response(request, response, *args, **kwargs)


class List(APIView):
    def list(self):
        queryset = self.filter_queryset(self.get_queryset())

        page = self.paginate_queryset(queryset)
        if page is not None:
            serializer = self.get_serializer(page, many=True)
            return self.get_paginated_response(serializer.data)

        serializer = self.get_serializer(queryset, many=True)
        return Response(serializer.data)

    def get_paginate(self):
        page = int(self.request.GET.get('page', 1) or 1)
        limit = int(self.request.GET.get('limit', 10) or 10)

        if page < 1:
            page = 1
        if limit < 1:
            limit = 1

        return page, limit


class Retrieve(APIView):
    def retrieve(self):
        self.kwargs[self.lookup_field] = self.kwargs.pop('id')
        instance = self.get_object()
        serializer = self.get_serializer(instance)
        return Response({'status': 'success', 'data': serializer.data})


class Create(APIView):
    def create(self):
        serializer = self.get_serializer(data=self.request.data)
        serializer.is_valid(raise_exception=True)
        self.perform_create(serializer)
        headers = self.get_success_headers(serializer.data)
        return Response(
            serializer.data, status=status.HTTP_201_CREATED, headers=headers
        )


class Update(APIView):
    """
    Update a model instance.
    """

    def update(self):
        self.kwargs[self.lookup_field] = self.kwargs.pop('id')
        partial = self.url_args.pop('partial', False)
        instance = self.get_object()
        serializer = self.get_serializer(
            instance, data=self.request.data, partial=partial
        )
        serializer.is_valid(raise_exception=True)
        self.perform_update(serializer)

        if getattr(instance, '_prefetched_objects_cache', None):
            # If 'prefetch_related' has been applied to a queryset, we need to
            # forcibly invalidate the prefetch cache on the instance.
            instance._prefetched_objects_cache = {}

        return Response({'status': 'success'})

    def perform_update(self, serializer):
        serializer.save()

    def partial_update(self, request, *args, **kwargs):
        kwargs['partial'] = True
        return self.update()


class Destroy(APIView):
    def destroy(self):
        instance = self.get_object()
        self.perform_destroy(instance)
        return Response(status=status.HTTP_204_NO_CONTENT)

    def perform_destroy(self, instance):
        instance.delete()


class APIViewCreate(Create):
    def post(self, request, *args, **kwargs):
        self._initialize(request, *args, **kwargs)
        return self.create()


class APIViewList(List):
    def get(self, request, *args, **kwargs):
        self._initialize(request, *args, **kwargs)
        return self.list()


class APIViewRetrieve(Retrieve):
    def get(self, request, *args, **kwargs):
        self._initialize(request, *args, **kwargs)
        return self.retrieve()


class APIViewUpdate(Update):
    def put(self, request, *args, **kwargs):
        self._initialize(request, *args, **kwargs)
        return self.update()


class APIViewDestroy(Destroy):
    def delete(self, request, *args, **kwargs):
        self._initialize(request, *args, **kwargs)
        return self.destroy()


class Success(Response):
    def __init__(self):
        super(Success, self).__init__(data={'status': 'success'})


class NotifySuccess(Success):
    def __init__(self, notify_redis=None, notify_id: str = None):
        super(NotifySuccess, self).__init__()
        if notify_redis and notify_id:
            notify_redis.set(f"notify_id:{notify_id}", 1, ex=300)


class NoticeForcedWaiting(Success):
    code = 201
    msg = 'Notice forced waiting'
